﻿//using System;
using System.Collections.Generic;
//using System.Text;
using System.IO;
using AMS.DeDuplicator.CommonLayer;
using AMS.DeDuplicator.CommonLayer.Composite;
using AMS.DeDuplicator.CommonLayer.Iterator;

namespace AMS.DeDuplicator.BusinessLayer
{
    public class DeDuplicatorClient
    {
        IDuplicateIdentifier _identifier;

        #region Delegates
        // consider Observer pattern alternative
        // internal getters; don't want outsides to be able to invoke these
        public HookDelegate StartingProcess { set; internal get; }
        public HookDelegate FinishedProcess { set; internal get; }
        public HookDelegate StartingDirectory { set; internal get; }
        public HookDelegate FinishedDirectory { set; internal get; }
        public HookDelegate StartingFile { set; internal get; }
        public HookDelegate FinishedFile { set; internal get; }
        #endregion

        public DeDuplicatorClient(IDuplicateIdentifier duplicateIdentifer)
        {
            InputValidator.ValidateNotNull(duplicateIdentifer);
            _identifier = duplicateIdentifer;
        }

        // consider having this method return a custom Composite Pattern object instead
        public Dictionary<string, List<string>> FindDuplicates(string startDirectory, bool recurse)
        {
            // Step 1: validate input directory
            InputValidator.ValidateDirectoryExists(startDirectory);

            // Reset _identifier
            _identifier.Reset();

            // Dictionary of some identifier to list of filepaths that match
            Dictionary<string, List<string>> duplicateMap = new Dictionary<string, List<string>>();

            IDirectoryComposite directory = new DirectoryComposite(startDirectory);

            // hook before start (ie, progress bar file count, console update)
            if (StartingProcess != null)
                StartingProcess(startDirectory);

            CheckFiles(directory, duplicateMap, recurse);

            // hook after done (console update)
            if (FinishedProcess != null)
                FinishedProcess(startDirectory);

            return duplicateMap;
        }

        protected virtual void CheckFiles(IDirectoryComposite directory, Dictionary<string, List<string>> duplicateMap, bool recurse)
        {
            // hook before starting directory
            if (StartingDirectory != null)
                StartingDirectory(directory.Path);

            // iterate over all files
            IIterator<IFileComponent> files = directory.GetFiles();
            while (files.HasNext())
            {
                IFileComponent file = files.GetNext();

                // hook before starting file
                if (StartingFile != null)
                    StartingFile(file.FullName);

                UniquePropertySet properties;
                string primeMatch;
                if (_identifier.CheckFile(file.FullName, out properties, out primeMatch))
                {
                    // there is a match, so make sure we're tracking
                    if (!duplicateMap.ContainsKey(primeMatch))
                    {
                        duplicateMap.Add(primeMatch, new List<string>(new string[] { file.FullName }));
                    }
                    else
                    {
                        duplicateMap[primeMatch].Add(file.FullName);
                    }
                }

                // hook after file (ie., progress bar update, console update)
                if (FinishedFile != null)
                    FinishedFile(file.FullName);
            }

            // hook after finished with directory
            if (FinishedDirectory != null)
                FinishedDirectory(directory.Path);

            // recurse
            if (recurse)
            {
                IIterator<IDirectoryComposite> subdirectories = directory.GetDirectories();
                while (subdirectories.HasNext())
                {
                    CheckFiles(subdirectories.GetNext(), duplicateMap, recurse);
                }
            }
        }
    }
}
